package com.h.extensions.controller;

import com.h.extensions.constant.Constants;
import jakarta.annotation.Resource;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.yaml.snakeyaml.scanner.Constant;

import java.util.Date;

@Controller
@RequestMapping("/producer")
public class ProducerController {
    @Resource(name = "rabbitTemplate")
    private RabbitTemplate rabbitTemplate;

    @Resource(name = "confirmRabbitTemplate")
    private RabbitTemplate confirmRabbitTemplate;

    @Resource(name = "transRabbitTemplate")
    private RabbitTemplate transRabbitTemplate;

    // 消息确认
    @RequestMapping("/ack")
    public String ack() {
        rabbitTemplate.convertAndSend(Constants.ACK_EXCHANGE, "", "onsumer ack mode test...");
        return "消费者确认，此时信息发送成功";
    }

    // 持久性测试，生产者
    @RequestMapping("/pres")
    public String pres() {
        String msg = "Presistent test...";
        Message message = new Message(msg.getBytes(),new MessageProperties());
        // 如果想要消息持久化的话，只是设置消息持久化还不够，还需要将队列也持久化才可以，如果队列非持久化而消息持久化也无用
        // 消息持久化
        message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
        // 消息非持久化
//        message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.NON_PERSISTENT);
        rabbitTemplate.convertAndSend(Constants.PRES_EXCHANGE, "pres",message);
        return "持久性测试，生产者发送成功";
    }

    // 发送方确认测试
    // confirm 的确认模式是解决 —— 生产者 和 交换机 之间的可靠性保证的问题
    @RequestMapping("/confirm")
    public String confirm() {
        CorrelationData correlationData = new CorrelationData("1");
        confirmRabbitTemplate.convertAndSend(Constants.CONFIRM_EXCHANGE, "confirm",
                "confirm test...",correlationData);
        return "发送方确认confirm模式测试，生产者发送成功";
    }

    // return 退回模式是解决 —— 交换机 和 队列 之间的可靠性保证的问题
    @RequestMapping("/return")
    public String returns() {
        CorrelationData correlationData = new CorrelationData("5");
        confirmRabbitTemplate.convertAndSend(Constants.CONFIRM_EXCHANGE, "confirm111",
                "returns test...", correlationData);
        return "发送方确认return退回模式测试，生产者发送成功";
    }

    // 重发机制
    @RequestMapping("/retry")
    public String retry() {
        System.out.println("retry.....");
        String msg = "retry test...";
        rabbitTemplate.convertAndSend(Constants.RETRY_EXCHANGE, "retry", msg);
        return "重发机制测试，生产者消息发送成功";
    }

    // ttl 过期时间、消息的寿命、存活时间
    // 当消息到达设置的过期时间还没有被消费掉，就会被清除掉
    // 如果消息和队列同时设置过期时间的话，那么对其过期时间就是他们之间设置的最小值就是过期时间
    @RequestMapping("/ttl1")
    public String ttl1() {
        // 设置消息的过期时间
        System.out.println("ttl1.....");
        String msg1 = "ttl1 test 30s...";
        String msg2 = "ttl2 test 10s...";

        // 写法一
//        MessagePostProcessor messagePostProcessor = new MessagePostProcessor() {
//            @Override
//            public Message postProcessMessage(Message message) throws AmqpException {
//                message.getMessageProperties().setExpiration("30000");
//                return message;
//            }
//        };
//        rabbitTemplate.convertAndSend(Constants.TTL_EXCHANGE, "ttl", msg1,messagePostProcessor);
        // 使用简单方式
        rabbitTemplate.convertAndSend(Constants.TTL_EXCHANGE, "ttl", msg1,
                messagePostProcessor -> {
            messagePostProcessor.getMessageProperties().setExpiration("30000");
            return messagePostProcessor;
            });

        rabbitTemplate.convertAndSend(Constants.TTL_EXCHANGE, "ttl", msg2,
                messagePostProcessor -> {
                    messagePostProcessor.getMessageProperties().setExpiration("10000");
                    return messagePostProcessor;
                });
        // 这样的消息发送存在问题，这样的30s在前10s在后，这样的方式需要再30s解决完，此能开始10s的ttl计算
        return "消息的ttl测试，生产者消息发送成功";
    }
    // 队列的ttl
    @RequestMapping("/ttl2")
    public String ttl2() {
        System.out.println("ttl2.....");
        // 发送普通额的信息
        String msg = "ttl test....";
        rabbitTemplate.convertAndSend(Constants.TTL_EXCHANGE, "ttl",msg);
        return "队列的ttl测试，生产者消息发送成功";
    }

    // 死信队列
    @RequestMapping("/dl")
    public String dl() {
        System.out.println("dl...");
        // 发送普通信息
        String msg = "dl test...";
        rabbitTemplate.convertAndSend(Constants.NORMAL_EXCHANGE, "normal", msg);
        System.out.printf("%tc 消息发送成功 /n", new Date());
        // 这个是用来测试长度那个条件的
//        for (int i = 0;i < 20;i++) {
//            rabbitTemplate.convertAndSend(Constants.NORMAL_EXCHANGE, "normal", msg + i);
//        }
        return "dl测试，生产者消息发送成功";
    }

    // 延迟队列 —— ttl + 死信队列实现
    // 监听死信队列，使用死信队列进行消费
    @RequestMapping("/delay1")
    public String delay1() {
        System.out.println("delay1...");
        String msg1 = "ttl1 test 30s...";
        String msg2 = "ttl2 test 10s...";

        rabbitTemplate.convertAndSend(Constants.NORMAL_EXCHANGE, "normal",msg1,message ->{
            message.getMessageProperties().setExpiration("30000");
            return message;
        });

        rabbitTemplate.convertAndSend(Constants.NORMAL_EXCHANGE, "normal",msg2,message ->{
            message.getMessageProperties().setExpiration("10000");
            return message;
        });

        return "delay测试，生产者消息发送成功";
    }

    // 延迟队列 —— 延迟队列的插件
    // 这样可以解决在 对于消息设置ttl的问题，这样使用插件之后就可以先是10，后是30，下述的代码中
    @RequestMapping("/delay2")
    public String delay2() {
        System.out.println("delay...");
        String msg1 = "delay1 test 30s...";
        String msg2 = "delay2 test 10s...";

        rabbitTemplate.convertAndSend(Constants.DELAY_EXCHANGE, "delay",msg1,message ->{
            message.getMessageProperties().setDelayLong(3000L);
            return message;
        });

        rabbitTemplate.convertAndSend(Constants.DELAY_EXCHANGE, "delay",msg2,message ->{
            message.getMessageProperties().setDelayLong(1000L);
            return message;
        });

        return "delay测试,延迟队列的插件，生产者消息发送成功";
    }

    // 事务
    // 在 RabbitTemplateConfig 进行特殊的声明，防止全部的 rabbitTemplate 都使用 事务
    // 需要创建RabbitMQ的事务管理器
    @Transactional // 必须存在
    @RequestMapping("/trans")
    public String trans() {
        System.out.println("trans...");
        String msg1 = "trans test 1...";
        String msg2 = "trans test 2...";
        transRabbitTemplate.convertAndSend("", Constants.TRANS_QUEUE,msg1);
        int sum = 3 / 0;
        transRabbitTemplate.convertAndSend("", Constants.TRANS_QUEUE, msg2);
        return "事务测试，生产者消息发送成功";
    }

    // 限流
    @RequestMapping("/qos")
    public String qos() {
        System.out.println("qos...");
        String msg = "qos test ...";
        for (int i = 0;i < 20;i++) {
            rabbitTemplate.convertAndSend(Constants.QOS_EXCHANGE, "qos", msg);
        }
        return "事务测试，生产者消息发送成功";
    }
}
